koa中间件案例：
const Koa = require('koa');
const app = new Koa();

app.use(async (ctx, next) => {
  console.log(1)
  await next()
  console.log(5)
});

app.use(async (ctx, next) => {
  console.log(2)
  await next();
  console.log(4)
});

app.use(async ctx => {
  console.log(3)
  ctx.body = 'Hello World';
});

app.listen(3000);
// 执行结果 1 2 3 4 5
// koa中间件 遇见 await next 方法，执行停住，执行权交给下一个中间件；
// 当下一个中间件执行完毕后，还有下一个中间件，继续向下交执行控制权；
// 如果没有下一个中间件了在返回当前中间件的上一个执行 await next 后面的代码，一直到最上面的中间件执行完毕
// 中间件按照顺序调用顺序执行

koa源码大致流程：
1 app.use() 方法 // koa/lib/application.js
  接收一个 函数(fn)，直接 push 到 中间件(middleware)的数组中
  this.middleware.push(fn)

2 this.middleware = [] // koa/lib/application.js

3 listen 方法
  利用 http 模块创建一个服务 createServer，入参是 callback
  const server = http.createServer(this.callback()); // koa/lib/application.js

4 callback 方法
  1) callback 函数主要就是取出所有的中间件 (middleware)，并处理回调，最后将 ctx 和 middleware 返回

    callback() {
      // 取所有中间件
      const fn = compose(this.middleware); // compose方法来源 koa/lib/application.js

      // 每个中间上有一个 ctx 这个是函数执行上下文
      // ctx 是由  koa/lib/context.js 创建的, 作用主要是代理 response 和 request 原型链上的方法
      // 所以 在 ctx 上能获取到 response request 上面的内容
      // response 来源 koa/lib/response.js
      // request 来源 koa/lib/request.js

      // handleRequest 处理回调
      const handleRequest = (req, res) => {
        // 创建上下文，把 ctx 传递进去，并代理 response 和 request 到 ctx 上
        const ctx = this.createContext(req, res);
        return this.handleRequest(ctx, fn);
      };

      // 返回处理过的 handleRequest
      return handleRequest;
    }
     
  2) compose 方法 // koa-compose/index.js
     compose 中 dispatch 的主要作用就是尾递归取所有的中间件(middleware)
     
     // compose 方法 具体实现如下
     function compose (middleware) {
      return function (context, next) {
        // last called middleware  最后调用的中间件
        let index = -1
        // 执行自己
        return dispatch(0)
        function dispatch (i) {
          if (i <= index) return Promise.reject(new Error('next() called multiple times'))
          index = i
          // 拿到指定位置的函数 即 中间件
          let fn = middleware[i] 
          // 当指定长度 i 等于 中间件数组的长度时，fn 直接等于 下一个函数值
          // 例如 middleware = [mid1, mid2, mid3], i = 3; 最后一个就没有内容了
          if (i === middleware.length) fn = next
          // 最后一个值时，执行的时空内容，直接返回一个 fulfilled 状态的 promise
          if (!fn) return Promise.resolve()
          try {
            // 递归，每次都在执行fn(context函数执行上下文, 下一个函数this绑定回去, i位置向下移动一位)
            // 即递归取出每一个中间件
            return Promise.resolve(fn(context, dispatch.bind(null, i + 1)));
          } catch (err) {
            return Promise.reject(err)
          }
        }
      }
    }

  